/*
/*
 * IconHandler - by Gil Schmidt
 * 
 * - Originaly was writtin for a p2p project called Kibutz.
 * - The IconFromExtension might give you some problems if it won't find an
 *   icon for it( try/catch should be used).
 *
 * [Updated]
 * 
 * - Added Shell function for getting file extension after getting some commet
 *   about it, check link below.
 *   (http://www.codeguru.com/Csharp/Csharp/cs_misc/icons/article.php/c4261/)
 * - IconFromResource was added for having all the common needed functions for 
 *   handling icons.
 * - Readed DestroyIcon and adding GetManagedIcon, after verifying it's needed 
 *   (thanks DrGui and Kenneth Broendum).
 * - Removed the IconFromExtension that pulled the icon from the registry 
 *   (IconFromExtensionShell is default now).
 * - Fixed IconCount mistake (if the number of icon in the file was 0 and the
 *   index that was selected was also 0 the ExtractIconEx still got to run and
 *   crashed (thanks SickLab).
 * - Fixed iIcon (it was changed from IntPtr to int. on x64 systems IntPtr is 
 *   8 bytes which caused the mistake to popup) parameter in SHFILEINFO struct 
 *   (Thanks Stefan Mayr).
 * 
 * contact me at: Gil_Smdt@Hotmail.com
 * 
*/

    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    using System.Reflection;
    using System.IO;

    namespace eeZeeFTP
    {
        struct SHFILEINFO
        {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        };

        public enum IconSize : uint
        {
            Large = 0x0,  //32x32

            Small = 0x1 //16x16        

        }

        /// <summary>
        /// Options to specify whether folders should be in the open or closed state.
        /// </summary>
        public enum FolderType
        {
            /// <summary>
            /// Specify open folder.
            /// </summary>
            Open = 0,
            /// <summary>
            /// Specify closed folder.
            /// </summary>
            Closed = 1
        }

        //the function that will extract the icons from a file

        public class IconHandler
        {
            const uint SHGFI_ICON = 0x100;
            const uint SHGFI_USEFILEATTRIBUTES = 0x10;
            const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
            const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
            const uint SHGFI_OPENICON = 0x000000002;     // get open icon
            const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
            const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;

            [DllImport("Shell32", CharSet = CharSet.Auto)]
            internal extern static int ExtractIconEx(
                [MarshalAs(UnmanagedType.LPTStr)] 
            string lpszFile,                //size of the icon

                int nIconIndex,
                //index of the icon (in case we have more 

                    //than 1 icon in the file

                IntPtr[] phIconLarge,           //32x32 icon

                IntPtr[] phIconSmall,           //16x16 icon

                int nIcons);                    //how many to get


            [DllImport("shell32.dll")]
            static extern IntPtr SHGetFileInfo(
                string pszPath,                //path

                uint dwFileAttributes,        //attributes

                ref SHFILEINFO psfi,        //struct pointer

                uint cbSizeFileInfo,        //size

                uint uFlags);    //flags


            //we need this function to release the unmanaged resource,

            //the unmanaged resource will be copies to a managed one and 

            //it will be returned.

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            extern static bool DestroyIcon(IntPtr handle);

            //will return an array of icons 

            public static Icon[] IconsFromFile(string Filename, IconSize Size)
            {
                int IconCount = ExtractIconEx(Filename, -1, null, null, 0);
                //checks how many icons.

                IntPtr[] IconPtr = new IntPtr[IconCount];
                Icon TempIcon;

                //extracts the icons by the size that was selected.

                if (Size == IconSize.Small)
                    ExtractIconEx(Filename, 0, null, IconPtr, IconCount);
                else
                    ExtractIconEx(Filename, 0, IconPtr, null, IconCount);

                Icon[] IconList = new Icon[IconCount];

                //gets the icons in a list.

                for (int i = 0; i < IconCount; i++)
                {
                    TempIcon = (Icon)Icon.FromHandle(IconPtr[i]);
                    IconList[i] = GetManagedIcon(ref TempIcon);
                }

                return IconList;
            }

            //extract one selected by index icon from a file.

            public static Icon IconFromFile(
                string Filename, IconSize Size, int Index)
            {
                int IconCount = ExtractIconEx(Filename, -1, null, null, 0);
                //checks how many icons.

                if (IconCount <= 0 || Index >= IconCount) return null;
                // no icons were found.


                Icon TempIcon;
                IntPtr[] IconPtr = new IntPtr[1];

                //extracts the icon that we want in the selected size.

                if (Size == IconSize.Small)
                    ExtractIconEx(Filename, Index, null, IconPtr, 1);
                else
                    ExtractIconEx(Filename, Index, IconPtr, null, 1);

                TempIcon = Icon.FromHandle(IconPtr[0]);

                return GetManagedIcon(ref TempIcon);
            }
            public static Icon IconFromExtension(string Extension, IconSize Size)
            {
                try
                {
                    Icon TempIcon;

                    //add '.' if nessesry

                    if (Extension[0] != '.') Extension = '.' + Extension;

                    //temp struct for getting file shell info

                    SHFILEINFO TempFileInfo = new SHFILEINFO();

                    SHGetFileInfo(
                        Extension,
                        0,
                        ref TempFileInfo,
                        (uint)Marshal.SizeOf(TempFileInfo),
                        SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | (uint)Size);

                    TempIcon = (Icon)Icon.FromHandle(TempFileInfo.hIcon);
                    return GetManagedIcon(ref TempIcon);
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine(
                        "error while trying to get icon for " + Extension +
                        " :" + e.Message);
                    return null;
                }
            }

            /*
             * this is the built in funcion provided by .Net framework for getting 
             * a file icon, i thought it's worth mentioning.
             * 
            public static Icon IconFromExtension(string Filename)
            {
                return Icon.ExtractAssociatedIcon(Filename);
            }
            */

            public static Icon IconFromResource(string ResourceName)
            {
                Assembly TempAssembly = Assembly.GetCallingAssembly();

                return new Icon(TempAssembly.GetManifestResourceStream(
                    ResourceName));
            }

            public static void SaveIconFromImage(
                Image SourceImage, string IconFilename, IconSize DestenationIconSize)
            {
                Size NewIconSize = DestenationIconSize ==
                    IconSize.Large ? new Size(32, 32) : new Size(16, 16);

                Bitmap RawImage = new Bitmap(SourceImage, NewIconSize);
                Icon TempIcon = Icon.FromHandle(RawImage.GetHicon());
                FileStream NewIconStream = new FileStream(
                    IconFilename, FileMode.Create);

                TempIcon.Save(NewIconStream);

                NewIconStream.Close();
            }

            public static void SaveIcon(Icon SourceIcon, string IconFilename)
            {
                FileStream NewIconStream = new FileStream(
                    IconFilename, FileMode.Create);

                SourceIcon.Save(NewIconStream);

                NewIconStream.Close();
            }

            public static Icon GetManagedIcon(ref Icon UnmanagedIcon)
            {
                Icon ManagedIcon = (Icon)UnmanagedIcon.Clone();

                DestroyIcon(UnmanagedIcon.Handle);

                return ManagedIcon;
            }

            /// <summary>
            /// Used to access system folder icons.
            /// </summary>
            /// <param name="size">Specify large or small icons.</param>
            /// <param name="folderType">Specify open or closed FolderType.</param>
            /// <returns>System.Drawing.Icon</returns>
            public static System.Drawing.Icon GetFolderIcon(IconSize size, FolderType folderType)
            {
                // Need to add size check, although errors generated at present!
                uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES;

                if (FolderType.Open == folderType)
                {
                    flags += SHGFI_OPENICON;
                }

                if (IconSize.Small == size)
                {
                    flags += SHGFI_SMALLICON;
                }
                else
                {
                    flags += SHGFI_LARGEICON;
                }

                // Get the folder icon
                SHFILEINFO shfi = new SHFILEINFO();
                SHGetFileInfo(@"c:\madeupdir",
                    FILE_ATTRIBUTE_DIRECTORY,
                    ref shfi,
                    (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
                    flags);

                System.Drawing.Icon.FromHandle(shfi.hIcon);	// Load the icon from an HICON handle

                // Now clone the icon, so that it can be successfully stored in an ImageList
                System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();

                DestroyIcon(shfi.hIcon);		// Cleanup
                return icon;
            }
        }
    }

    /* EOF */
